#pragma once
#include "requestor.hpp"

namespace jsonrpc
{
    // 客户端和服务端的接口可能重合
    namespace client
    {   
        // 给用户提供接口
        class RpcCaller
        {
        public:
            RpcCaller(const Requestor::ptr& requestor):_requestor(requestor){}
        public:
            using ptr = std::shared_ptr<RpcCaller>;
            using JsonAsyncResponse = std::future<Json::Value>;
            using JsonResponseCallback = std::function<void(const Json::Value&)>;
            // requestor中的处理是针对BaseMessage处理的
            // rpa_caller中的处理是针对RpcResponse里边的result进行处理
            // 同步
            bool call(const BaseConnection::ptr& conn, const std::string &method, const Json::Value& params, Json::Value& result)
            {
                //1. 组织请求
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(UUID::uuid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setparameters(params);
                BaseMessage::ptr rsp_msg;
                //2. 发送请求
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), rsp_msg);
                if (ret == false) 
                {
                    ELOG("同步Rpc请求失败!");
                    return false;
                }
                //3. 等待响应
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(rsp_msg);
                if(rpc_rsp_msg.get() == nullptr)
                {
                    ELOG("rpc响应, 向下类型转换失败! ");
                    return false;
                }

                if(rpc_rsp_msg->rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc请求出错: %s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return false;
                }
                result = rpc_rsp_msg->result();
                DLOG("结果设置完毕!");
                return true;
            }

            // 异步 -- 这里返回给用户的是正文
            bool call(const BaseConnection::ptr& conn, const std::string &method, const Json::Value& params, JsonAsyncResponse& result)
            {
                //1. 向服务器发送异步回调请求, 设置回调函数, 回调函数中会传入一个promise对象, 在回调函数中通过promise设置数据(外面的future获取结果)
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(UUID::uuid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setparameters(params);

                //2. 发送请求  -- promise这里是局部变量(出了作用域就销毁了), 改成智能指针对象
                auto json_promise = std::make_shared<std::promise<Json::Value>>();
                result = json_promise->get_future();
                // 传递promise, 让其它线程去执行想要执行的函数, 再设置结果
                Requestor::ReqCallBack callback = std::bind(&RpcCaller::CallBack_Promise, this, json_promise, std::placeholders::_1);
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), callback);
                if(ret == false)
                {
                    ELOG("异步请求失败");
                    return false;
                }
                return true;
            }

            // 回调
            bool call(const BaseConnection::ptr& conn, const std::string &method, const Json::Value& params, const JsonResponseCallback& cb)
            {
                // 1.组织请求
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(UUID::uuid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setparameters(params);
                // 2.发送请求
                Requestor::ReqCallBack req_callback = std::bind(&RpcCaller::CallBack, this, cb, std::placeholders::_1);
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), req_callback);
                if(ret == false)
                {
                    ELOG("回调Rpc请求失败");
                    return false;
                }
                return true;
            }

        private:
            // 处理回调函数的实现
            void CallBack(const JsonResponseCallback& cb, const BaseMessage::ptr& msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if(rpc_rsp_msg.get() == nullptr)
                {
                    ELOG("异步响应, 向下类型转换失败! ");
                    return ;
                }

                if(rpc_rsp_msg->rcode() != RCode::RCODE_OK)
                {
                    ELOG("回调请求出错: %s", errReason(rpc_rsp_msg->rcode()));
                    return ;
                }
                // 根据结果进行处理
                cb(rpc_rsp_msg->result());
            }

            // 处理异步RPC请求的回调函数 -- Promise拿到结果后设置结果, 外面的直接获取
            void CallBack_Promise(std::shared_ptr<std::promise<Json::Value>> result, const BaseMessage::ptr& msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if(rpc_rsp_msg.get() == nullptr)
                {
                    ELOG("异步响应, 向下类型转换失败! ");
                    return ;
                }

                if(rpc_rsp_msg->rcode() != RCode::RCODE_OK)
                {
                    ELOG("异步请求出错: %s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return ;
                }
                result->set_value(rpc_rsp_msg->result());
            }

        private:
            Requestor::ptr _requestor;
        };
    }
}